package com.myidis.servlet;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.auxiliary.BBForPeakValley;
import com.auxiliary.BasicCalculator;
import com.auxiliary.CorrelationLine;
import com.auxiliary.Inflexion;
import com.auxiliary.KLInformation;
import com.auxiliary.PeakValleyCalculator;
import com.auxiliary.QuotaDataFinder;
import com.auxiliary.SeasonAdjuster;
import com.auxiliary.TimeCorrelation;
import com.auxiliary.TimeSequence;
import com.myidis.entity.AnalysisResult;
import com.myidis.entity.QuotaData;
import com.myidis.mapper.AnalysisResultMapper;
import com.myidis.mapper.QuotaDataMapper;
import com.myidis.mapper.QuotaMapper;
import com.myidis.request.CorrelationReq;
import com.myidis.request.PeakValleyReq;
import com.myidis.request.CheckReq;
import com.myidis.request.BBReq;
import com.myidis.request.SeasonAdjustReq;
import com.myidis.response.BBRes;
import com.myidis.response.CorrelationRes;
import com.myidis.response.PeakValleyRes;
import com.myidis.response.SeasonAdjustRes;
import com.myidis.response.StatisticsRes;

@Service
public class AnalysisServlet {
	@Autowired
	private QuotaMapper quotaMapper;
	@Autowired
	private QuotaDataMapper quotaDataMapper;
	@Autowired
	private AnalysisResultMapper anaResMapper;
	
	/*
	 * 检查数据的完整性，若完整返回1，否则返回null
	 * @param CheckReq
	 * @return Integer
	 */
	public Integer check(CheckReq req) {
		//若指标数组为空或没有数据，返回null
		if(req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//对所有分析指标进行完整性检查，不需要进行季节调整，若都完整则返回1，否则返回null
		if(checkListIntegrality(req, false) != null)
			return 1;
		else
			return null;
	}
	
	/*
	 * 计算基本统计量，计算前先检查数据完整性，若不完整，返回null
	 * @param CheckReq
	 * @return List<StatisticsRes>
	 */
	public List<StatisticsRes> statistics(CheckReq req) {
		//若指标数组为空或没有数据，返回null
		if(req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//建立时间序列类TimeSequence集合，并进行数据完整性检查，不需要进行季节调整
		List<TimeSequence> sequenceList = checkListIntegrality(req, false);
		
		//若时间序列集合为null，说明数据完整性检查不通过，返回null
		if(sequenceList == null)
			return null;
		
		//建立计算类BasicCalculator对象
		BasicCalculator bc = new BasicCalculator();
		
		//建立基本统计量结果类集合List<StatisticsRes>
		List<StatisticsRes> list = new ArrayList<StatisticsRes>();
		
		//对每个指标进行基本统计量计算
		for(TimeSequence sequence: sequenceList) {
			
			double max = bc.getMax(sequence.getValueList());
			double min = bc.getMin(sequence.getValueList());
			double avg = bc.calcAvg(sequence.getValueList());;
			double stdev = bc.calcStdev(sequence.getValueList());
			double mid = bc.calcMedian(sequence.getValueList());
			double kurtosis = bc.calcKurtosis(sequence.getValueList());
			double skewness = bc.calcSkewness(sequence.getValueList());
			
			list.add(new StatisticsRes(max, min, avg, stdev, mid, kurtosis, skewness));
		}
		
		//返回结果
		return list;
	}
	
	/*
	 * 进行季节调整，调整前先检查数据完整性，若不完整，返回null
	 * @param SeasonAdjustReq
	 * @return SeasonAdjustRes
	 */
	public SeasonAdjustRes seasonAdjust(SeasonAdjustReq req) {
		//若指标id为0，说明数据错误，返回null
		if(req.getQuota() == 0)
			return null;
		
		//进行数据完整性检查
		TimeSequence sequence = checkIntegrality(new QuotaDataFinder(req.getQuota(), req));
		//若不通过返回null
		if(sequence == null)
			return null;
		
		//进行季节调整
		SeasonAdjuster adjust = new SeasonAdjuster(sequence, req.getFrequency(), 1);
		
		//返回季节调整后序列
		return new SeasonAdjustRes(req.getCheckBox(), adjust);
	}
	
	/*
	 * 进行相关性分析，计算前先检查数据完整性，若不完整，返回null
	 * @param CorrelationReq
	 * @return CorrelationRes
	 */
	public CorrelationRes correlation(CorrelationReq req) {
		//若基准指标或分析指标数组为空或没有数据，返回null
		if(req.getBaseQuota() == null || req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//对基准指标进行数据完整性检查
		TimeSequence baseSequence = checkIntegrality(new QuotaDataFinder(req.getBaseQuota(), req));
		//若不通过则返回null
		if(baseSequence == null)
			return null;	
		
		//建立时间序列类TimeSequence集合，并进行数据完整性检查，并按情况进行季节调整进行季节调整
		List<TimeSequence> analysisSequence = checkListIntegrality(req, req.isSeasonAdjust());
		
		//若需要进行季节调整，对基准指标进行季节调整
		if(req.isSeasonAdjust()){
			SeasonAdjuster adjust = new SeasonAdjuster(baseSequence, req.getFrequency(), 1);	
			baseSequence.setValueList(adjust.getTCList());
		}
		
		//创建相关性结果类CorrelationRes
		CorrelationRes res = new CorrelationRes();
		
		//创建指标名称集合
		List<String> lineNames = new ArrayList<String>();
		
		//对各个指标进行相关性分析
		for(TimeSequence analysis: analysisSequence) {
			//获取指标名称，并添加到集合
			String quotaName = quotaMapper.getOne(analysis.getQuota()).getChineseName();
			lineNames.add(quotaName);
			
			//通过用户提交信息判断进行何种相关性分析
			for(int type: req.getCheckBox()) {
				//若为1进行时差相关性分析，否则进行KL信息量分析
				if(type == 1) {
					//时差相关性分析
					CorrelationLine timeLine = TimeCorrelation.calc(baseSequence.getValueList(), analysis.getValueList());
					//设置时差相关性图形对应的指标名称，并把结果存入返回类中
					timeLine.setName(quotaName);
					res.getTimeLineList().add(timeLine);
					
					//保存分析结果
					anaResMapper.insert(new AnalysisResult(baseSequence.getQuota(), analysis.getQuota(), 1, req.getStartTime(), req.getEndTime(), timeLine.toString(), 1));
				}
				else {
					//KL信息量分析
					CorrelationLine klLine = KLInformation.calc(baseSequence.getValueList(), analysis.getValueList());
					//设置KL信息量图形对应的指标名称，把结果存入返回类中
					klLine.setName(quotaName);
					res.getKlLineList().add(klLine);
					
					//保存分析结果
					AnalysisResult save = new AnalysisResult(baseSequence.getQuota(), analysis.getQuota(), 2, req.getStartTime(), req.getEndTime(), klLine.toString(), 1);
					if(anaResMapper.getByCon(save) != null)
						anaResMapper.update(save);
					else
						anaResMapper.insert(save);
				}
			}
						
			
		}
		//为返回类配置指标名称集合
		res.setLineNames(lineNames);
		
		return res;
	}
	
	/*
	 * 进行谷峰图形绘制，计算前先检查数据完整性，若不完整，返回null
	 * @param BBReq
	 * @return List<BBRes>
	 */
	public BBRes calcBB(BBReq req) {
		//若基准指标或分析指标数组为空或没有数据，返回null
		if(req.getBaseQuota() == null || req.getAnalysisQuota() == null || req.getAnalysisQuota().length <= 0)
			return null;
		
		//对基准指标进行数据完整性检查
		TimeSequence baseSequence = checkIntegrality(new QuotaDataFinder(req.getBaseQuota(), req));
		//若不通过则返回null
		if(baseSequence == null)
			return null;	
		
		/*
		//建立时间序列类TimeSequence集合，并进行数据完整性检查，并按情况进行季节调整进行季节调整
		List<TimeSequence> analysisSequence = checkListIntegrality(req, req.isSeasonAdjust());
		*/
		
		//建立时间序列类TimeSequence集合，用于存储完整性检查通过的时间序列
		List<String> quotaNames = new ArrayList<String>();
		List<TimeSequence> analysisSequence = new ArrayList<TimeSequence>();
		List<List<Double>> analysisTCs = new ArrayList<List<Double>>();
		
		
		//通过循环遍历指标数组进行完整性检查
		for(int id: req.getAnalysisQuota()) {
			
			//检查指标analysis的数据完整性
			TimeSequence temp = checkIntegrality(new QuotaDataFinder(id, req));
			
			//若返回为null，证明数据不完整，直接返回null
			if(temp == null)
				return null;
			
			quotaNames.add(quotaMapper.getOne(id).getChineseName());
			
			SeasonAdjuster adjust = new SeasonAdjuster(temp, req.getFrequency(), 1);	
			analysisTCs.add(adjust.getTCList());
			
			//若检查通过，则添加到集合中
			analysisSequence.add(temp);
		}
		
		BBRes res = new BBRes();
		
		res.setAnaQuotaNames(quotaNames);
		res.setBaseQuotaName(quotaMapper.getOne(req.getBaseQuota()).getChineseName());
		
		SeasonAdjuster adjust = new SeasonAdjuster(baseSequence, req.getFrequency(), 1);
		//若需要进行季节调整，对基准指标进行季节调整
		if(req.isSeasonAdjust()){
			baseSequence.setValueList(adjust.getSAList());
		}
		
		res.setxAxis(adjust.getxAxis());
			
		//计算基准指标的峰谷
		BBForPeakValley bb = new BBForPeakValley(baseSequence, req.getHalfPeriod(), req.getOnePeriod());
		
		res.setBaseInflexion(bb.calc().getReturn());
		
		//计算各分析指标的峰谷
		for(TimeSequence analysis: analysisSequence) {
			bb = new BBForPeakValley(analysis, req.getHalfPeriod(), req.getOnePeriod());
			
			List<String> temp = bb.calc().getReturn();
			temp.add(0, "--");
			
			res.getAnaInflexion().add(temp);
		}
		
		return res;
	}
	
	/*
	 * 进行谷峰图形分析
	 * @param PeakValleyReq
	 * @return List<String>
	 */
	public List<PeakValleyRes> calcPeakValley(PeakValleyReq req) {
		//结果字符串
		List<PeakValleyRes> res = new ArrayList<PeakValleyRes>();
		
		//根据所给拐点（峰或谷）进行分析
		for(int i = 0; i < req.getAnalysisQuota().length; i++) {
			List<Inflexion>[] infListArray = toInflexionArray(req.getBasePV(), req.getAnasPV().get(i));
			
			if(infListArray == null)
				return null;
				
			PeakValleyRes temp = PeakValleyCalculator.Calculate(infListArray[0], infListArray[1]);
			
			String resStr = "无法计算，原因可能是峰谷不对应造成的，必须峰对蜂、谷对谷，或者传入的峰谷数据不足";
			
			if(temp == null)
				temp = new PeakValleyRes(quotaMapper.getOne(req.getAnalysisQuota()[i]).getChineseName(), resStr);
			else
				resStr = temp.getResult(quotaMapper.getOne(req.getAnalysisQuota()[i]).getChineseName());
			
			res.add(temp);
			
			AnalysisResult save = new AnalysisResult(req.getBaseQuota(), req.getAnalysisQuota()[i], 2, req.getStartTime(), req.getEndTime(), resStr, 1);
			if(anaResMapper.getByCon(save) != null)
				anaResMapper.update(save);
			else
				anaResMapper.insert(save);
		}
		
		/*
		for(List<Inflexion> anaInfx: req.getAnasInfx()) {
			PeakValleyRes temp = PeakValleyCalculator.Calculate(req.getBaseInfx(), anaInfx);
			
			res.add(temp.toString());
			
			anaResMapper.insert(new AnalysisResult(req.getBaseQuota(), req.getAnalysisQuota()[i], 2, req.getStartTime(), req.getEndTime(), temp.toString(), 1));
			i++;
		}
		*/
		return res;
	}
	
	private List<Inflexion>[] toInflexionArray(List<String> basePV, List<String> anaPV) {
		
		List<Inflexion>[] infListArray = new ArrayList[2];
		
		infListArray[0] = new ArrayList<Inflexion>();
		infListArray[1] = new ArrayList<Inflexion>();
		
		for(int i = 0; i < basePV.size(); i++) {
			if(anaPV.get(i).equals("--"))
				continue;
			
			String[] baseSplit = basePV.get(i).split("（");
			String[] anaSplit = anaPV.get(i).split("（");
			
			if(!baseSplit[1].equals(anaSplit[1]))
				continue;
			
			infListArray[0].add(new Inflexion(baseSplit[0], baseSplit[1].equals("峰）")? true: false));
			infListArray[1].add(new Inflexion(anaSplit[0], anaSplit[1].equals("峰）")? true: false));
		}
		
		/*
		BasicCalculator bc = new BasicCalculator();
		
		for(String one: baseList) {
			String[] split = one.split("（");
			
			infList.add(new Inflexion(split[0], split[1].equals("峰）")? true: false));
		}
		*/
		
		return infListArray;
	}
	
	//复合一致指标
	public List<Double> comcQuota(SeasonAdjustReq req) {
		TimeSequence sequence = checkIntegrality(new QuotaDataFinder(req.getQuota(), req));
		
		if(sequence == null)
			return null;
		
		SeasonAdjuster adjust = new SeasonAdjuster(sequence, req.getFrequency(), 1);
		
		
		return null;
	}
	
	/*
	 * 检查一个指标数据的完整性，不完整返回null，否则返回时间序列类TimeSequence
	 * @param QuotaDataFinder
	 * @return TimeSequence
	 */
	public TimeSequence checkIntegrality(QuotaDataFinder check) {
		BasicCalculator bc = new BasicCalculator();
		
		int count = bc.getDataCount(check.getStartTime(), check.getEndTime());
		
		List<QuotaData> temp = quotaDataMapper.getByQuotaWithOther(check);
		TimeSequence dataList = new TimeSequence(temp);
		
		if(dataList.getDataCount() == count)
			return dataList;
		else
			return null;
	}
	
	/*
	 * 检查一组指标数据的完整性，不完整返回null，否则返回时间序列类集合List<TimeSequence>
	 * @param CheckReq
	 * @return List<TimeSequence>
	 */
	public List<TimeSequence> checkListIntegrality(CheckReq req, boolean seasonAdjust) {
		//建立时间序列类TimeSequence集合，用于存储完整性检查通过的时间序列
		List<TimeSequence> sequenceList = new ArrayList<TimeSequence>();
		
		//通过循环遍历指标数组进行完整性检查
		for(int id: req.getAnalysisQuota()) {
			
			//检查指标analysis的数据完整性
			TimeSequence temp = checkIntegrality(new QuotaDataFinder(id, req));
			
			//若返回为null，证明数据不完整，直接返回null
			if(temp == null)
				return null;
			
			//若需要进行季节调整，则对该指标进行季节调整
			if(seasonAdjust){
				SeasonAdjuster adjust = new SeasonAdjuster(temp, req.getFrequency(), 1);	
				temp.setValueList(adjust.getTCList());
			}
			
			//若检查通过，则添加到集合中
			sequenceList.add(temp);
		}
		
		//若所有指标完整性检查都通过，则返回时间序列集合
		return sequenceList;
	}
}

